package com.boss.thirteen.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.boss.asset.service.IAssetInfoService;
import com.boss.common.entity.PageDTO;
import com.boss.common.service.ICommonService;
import com.boss.config.FileServiceConfiguration;
import com.boss.framework.dto.PaginationDTO;
import com.boss.framework.exception.AppRuntimeException;
import com.boss.salary.constant.ApiElementConstant;
import com.boss.salary.constant.SystemDictConstant;
import com.boss.salary.dao.IAgencyInfoDao;
import com.boss.salary.dao.IFileSendLogDao;
import com.boss.salary.dao.ISalaryBasedataDao;
import com.boss.salary.entity.SalaryBasedata;
import com.boss.sys.ca.user.dto.UserDTO;
import com.boss.sys.utils.SysUtils;
import com.boss.thirteen.dao.ISalaryThirteenMonthDao;
import com.boss.thirteen.dao.ISalaryThirteenMouldDao;
import com.boss.thirteen.dao.IThirteenAgencyVerifyDao;
import com.boss.thirteen.dao.IThirteenGenerateBankDataDao;
import com.boss.thirteen.entity.ThirteenAgencyVerify;
import com.boss.thirteen.service.IThirteenGenerateBankDataService;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ThirteenGenerateBankDataServiceImpl implements IThirteenGenerateBankDataService {

    private static final Logger LOG = LoggerFactory.getLogger(ThirteenGenerateBankDataServiceImpl.class);
    /**
     * 引入接口服务配置类
     */
    @Autowired
    private FileServiceConfiguration fileServiceConfiguration;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ICommonService commonService;

    @Autowired
    private IThirteenGenerateBankDataDao generateBankDataDao;
    @Autowired
    private IThirteenAgencyVerifyDao agencyVerifyDao;
    @Autowired
    private ISalaryThirteenMouldDao salaryThirteenMouldDao;
    @Autowired
    private IAgencyInfoDao agencyInfoDao;
    @Autowired
    private ISalaryThirteenMonthDao salaryThirteenMonthDao;
    @Autowired
    private IFileSendLogDao fileSendLogDao;
    @Autowired
    private ISalaryBasedataDao salaryBasedataDao;
    @Autowired
    private IAssetInfoService assetInfoService;

    @Override
    public PageDTO<Map<String,Object>> getGenerateBankDataPage(PaginationDTO paginationDTO, Map<String, Object> queryForm, UserDTO userDTO, String tokenid) {
        PageDTO<Map<String,Object>> pageDTO = new PageDTO<>();
        List<String> agencyIds;
        if(StringUtils.isEmpty(queryForm.get("agencyId"))){
            agencyIds = commonService.getAgencyChildrenId(userDTO, "0", tokenid);
        }else{
            String parentId = String.valueOf(queryForm.get("agencyId"));
            agencyIds = commonService.getAgencyChildrenId(userDTO, parentId,tokenid);
        }
        queryForm.put("province",userDTO.getProvince());
        List<Map<String,Object>> salaryDataVoList = generateBankDataDao.selectGenerateBankDataPage(paginationDTO, agencyIds, queryForm);
        int total = generateBankDataDao.selectGenerateBankDataTotal(agencyIds, queryForm);

        pageDTO.setRows(salaryDataVoList);
        pageDTO.setTotal(total);
        return pageDTO;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadBankData(String province,String sendBankCode) throws AppRuntimeException {
        JSONObject json = uploadSalaryData(province,sendBankCode);
        String rscode = String.valueOf(json.get("rscode"));
        if(SystemDictConstant.SUCCESS_CODE.equals(rscode)){
            List<ThirteenAgencyVerify> agencyVerify = agencyVerifyDao.getAgencyVerifyBySalaryBank(sendBankCode,province);
            agencyVerifyDao.batchUpdateAgencyVerifyBankStatus(agencyVerify,"1");
        }else{
            String message = String.valueOf(json.get("result"));
            LOG.warn("上传银行工资数据：{}",message);
            throw new AppRuntimeException(message);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JSONObject uploadSalaryData(String province,String sendBankCode) throws AppRuntimeException {
        String url = fileServiceConfiguration.getFileservice()+"/v1/salary/salaryFile";
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("province", province);
        paramMap.add("sendBankCode", sendBankCode);//生成文件银行编码
        HttpHeaders headers = new HttpHeaders();
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);
        JSONObject json = restTemplate.postForEntity(url, httpEntity, JSONObject.class).getBody();
        if(!StringUtils.isEmpty(json) && !StringUtils.isEmpty(json.get("rscode"))){
            return json;
        }else{
            LOG.warn("未请求到文件服务或文件服务返回值异常！");
            throw new RuntimeException("请求文件服务失败！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void regenerateBankData(String province,String sendBankCode) throws AppRuntimeException {
//      调用文件生成服务
        JSONObject json = generateBankData(province,sendBankCode);
        String rscode = String.valueOf(json.get("rscode"));
        if(SystemDictConstant.SUCCESS_CODE.equals(rscode)){
            List<ThirteenAgencyVerify> agencyVerify = agencyVerifyDao.getAgencyVerifyBySalaryBank(sendBankCode,province);
            agencyVerifyDao.batchUpdateAgencyVerifyBankStatus(agencyVerify,"0");
        }else{
            String message = String.valueOf(json.get("result"));
            LOG.warn("重新生成银行工资数据：{}",message);
            throw new AppRuntimeException(message);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JSONObject generateBankData(String province,String sendBankCode) throws AppRuntimeException {
        String url = fileServiceConfiguration.getFileservice()+"/v1/salary/generateSalaryFile";
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("province", province);
        paramMap.add("sendBankCode", sendBankCode);//生成文件银行编码
        HttpHeaders headers = new HttpHeaders();
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);
        JSONObject json = restTemplate.postForEntity(url, httpEntity, JSONObject.class).getBody();
        if(!StringUtils.isEmpty(json) && !StringUtils.isEmpty(json.get("rscode"))){
            return json;
        }else{
            LOG.warn("未请求到文件服务或文件服务返回值异常！");
            throw new RuntimeException("请求文件服务失败！");
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void ungenerateBankData(String province,String sendBankCode) throws AppRuntimeException {
//        调用文件生成服务
        JSONObject json = ungenerateSalaryData(province,sendBankCode);
        String rscode = String.valueOf(json.get("rscode"));
        if(SystemDictConstant.SUCCESS_CODE.equals(rscode)){
            List<ThirteenAgencyVerify> agencyVerify = agencyVerifyDao.getAgencyVerifyBySalaryBank(sendBankCode,province);
            agencyVerifyDao.batchUpdateAgencyVerifyBankStatus(agencyVerify,"0");
        }else{
            String message = String.valueOf(json.get("result"));
            LOG.warn("撤销生成银行工资数据：{}",message);
            throw new AppRuntimeException(message);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JSONObject ungenerateSalaryData(String province,String sendBankCode) throws AppRuntimeException {
        String url = fileServiceConfiguration.getFileservice()+"/v1/salary/ungenerateSalaryFile";
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("province", province);
        paramMap.add("sendBankCode", sendBankCode);//生成文件银行编码
        HttpHeaders headers = new HttpHeaders();
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);
        JSONObject json = restTemplate.postForEntity(url, httpEntity, JSONObject.class).getBody();
        if(!StringUtils.isEmpty(json) && !StringUtils.isEmpty(json.get("rscode"))){
            return json;
        }else{
            LOG.warn("未请求到文件服务或文件服务返回值异常！");
            throw new RuntimeException("请求文件服务失败！");
        }
    }

    @Override
    public void generateBankData(String province,Map<String,Object> queryForm) throws AppRuntimeException {
        List<String> agencyIds=agencyInfoDao.getAgencyIdsByBank(queryForm);
//        调用文件生成服务
        JSONObject json = generateBankData(province,queryForm.get("salaCardBank").toString());
        String rscode = String.valueOf(json.get("rscode"));
        if(!SystemDictConstant.SUCCESS_CODE.equals(rscode)){
            String message = String.valueOf(json.get("result"));
            LOG.warn("生成银行工资数据：{}",message);
            throw new AppRuntimeException(message);
        }
        List<ThirteenAgencyVerify> agencyVerifys=new ArrayList<>();
        for(String agencyid:agencyIds){
            ThirteenAgencyVerify agencyVerify = new ThirteenAgencyVerify();
            agencyVerify.setAgencyId(agencyid);
            agencyVerifys.add(agencyVerify);
        }
        agencyVerifyDao.batchUpdateAgencyVerifyBankStatus(agencyVerifys,SystemDictConstant.IS_GENERTE_NO_SEND+"");

    }

    @Override
    public boolean verifyFileState(String province) {
        int count = fileSendLogDao.selectNoSendFileCount(province);
        return count > 0;
    }

    /**
     * 导出银行文件查询明细
     * @param userDTO
     * @param outputStream
     * @throws IOException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateBankDataService(UserDTO userDTO, OutputStream outputStream) throws IOException {
        //获取人员类型查询工资项
        String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
        List<String> columnNameList=salaryThirteenMouldDao.queryMouldSalaryCodes(null,userDTO.getProvince(),year);
        List<String> request=new ArrayList<>();
        for(String salaryCode:columnNameList){
            request.addAll(Arrays.asList(salaryCode.split(",")));
        }
        List<String> currentColumnList = request.stream().distinct().collect(Collectors.toList());
//        工资编码list
        List<SalaryBasedata> sb=salaryBasedataDao.selectAllSalary(userDTO.getProvince());
        Map<String ,String > salaryNameMap=sb.stream().collect(Collectors.toMap(SalaryBasedata::getSalaryCode, SalaryBasedata::getSalaryName));
        //从平台接口获取银行编码和名称
        List<Map<String,String>> payeeAccts = assetInfoService.getBaseDataSelect(ApiElementConstant.SALBANK,userDTO.getProvince());;
        Map<String, Sheet> bankJoinOfferMap = new HashMap<>();
        Workbook workbook = new HSSFWorkbook();
        for(Map<String,String> payeeAcct : payeeAccts){
            String salaCardCode = payeeAcct.get("code");
            String bankName = payeeAcct.get("name");
            Sheet sheet = workbook.createSheet(bankName);
            Row row = sheet.createRow(0);
            for(int i = 0; i < 5; i++){
                Cell cell = row.createCell(i, CellType.STRING);
                switch (i){
                    case 0: cell.setCellValue("单位编码"); break;
                    case 1: cell.setCellValue("单位名称"); break;
                    case 2: cell.setCellValue("工资卡号"); break;
                    case 3: cell.setCellValue("姓名"); break;
                    case 4: cell.setCellValue("身份证号码"); break;
                }
            }
            for(int i = 0; i < currentColumnList.size(); i++){
                Cell cell = row.createCell(i + 5, CellType.STRING);
                cell.setCellValue(salaryNameMap.get(currentColumnList.get(i)));
            }
            bankJoinOfferMap.put(salaCardCode, sheet);
        }

        //获取可以生成得所有人员工资信息
        List<Map<String,Object>> list = salaryThirteenMonthDao.selectMXOffer(userDTO.getProvince(), currentColumnList);
            if(!CollectionUtils.isEmpty(list)) {
                for(Map<String, Object> offer : list) {
                    String salaCardBank = String.valueOf(offer.get("salaCardBank"));
                    Sheet sheet = bankJoinOfferMap.get(salaCardBank);
                    int rowIndex = sheet.getPhysicalNumberOfRows();
                    Row row = sheet.createRow(rowIndex);
                    for(int i = 0; i < 5; i++){
                        Cell cell = row.createCell(i, CellType.STRING);
                        switch (i){
                            case 0: cell.setCellValue(String.valueOf(offer.get("agencyCode"))); break;
                            case 1: cell.setCellValue(String.valueOf(offer.get("agencyName"))); break;
                            case 2: cell.setCellValue(String.valueOf(offer.get("salaCardNo"))); break;
                            case 3: cell.setCellValue(String.valueOf(offer.get("personName"))); break;
                            case 4: cell.setCellValue(String.valueOf(offer.get("idenNo"))); break;
                        }
                    }
                    for(int i = 0; i < currentColumnList.size(); i++){
                        Cell cell = row.createCell(i + 5, CellType.STRING);
                        String column = currentColumnList.get(i);
                        if("0".equals(column)){
                            cell.setCellValue("0");
                        }else{
                            cell.setCellValue(String.valueOf(offer.get(column)));
                        }
                    }
                }
            }
        workbook.write(outputStream);
        outputStream.close();
//        修改银行数据生成状态
        List<ThirteenAgencyVerify> agencyVerifys=new ArrayList<>();
        for(Map<String,String> payeeAcct : payeeAccts) {
            List<ThirteenAgencyVerify> agencyVerify = agencyVerifyDao.getAgencyVerifyBySalaryBank(payeeAcct.get("code"), userDTO.getProvince());
            agencyVerifys.addAll(agencyVerify);
        }
        if(!SysUtils.isNullOrEmpty(agencyVerifys)) {
            agencyVerifyDao.batchUpdateAgencyVerifyBankStatus(agencyVerifys, SystemDictConstant.IS_SUBMIT);
        }
    }

    @Override
    public List<Map<String, Object>> getGenerateMessage(Map<String, Object> queryForm, UserDTO userDTO,String tokenid) {
        List<Map<String, Object>> requestList=new ArrayList<>();
        if(StringUtils.isEmpty(queryForm.get("salaCardBank"))&&StringUtils.isEmpty(queryForm.get("menuid"))){//若未传银行参数，择不显示任何内容
            return requestList;
        }
        List<String> agencyIds;
        if(StringUtils.isEmpty(queryForm.get("agencyId"))){
            agencyIds = commonService.getAgencyChildrenId(userDTO, "0",tokenid);
        }else{
            String parentId = String.valueOf(queryForm.get("agencyId"));
            agencyIds = commonService.getAgencyChildrenId(userDTO, parentId,tokenid);
        }
        if(!StringUtils.isEmpty(queryForm.get("agencySelected"))){
            agencyIds= Arrays.asList(queryForm.get("agencySelected").toString().split(","));
        }
        queryForm.put("province",userDTO.getProvince());

        // 查询生成信息
        requestList = generateBankDataDao.getGenerateMessage( queryForm,agencyIds);
        return requestList;
    }

    @Override
    public void revokeGenerate(String province) {
        agencyVerifyDao.revokeGenerate(province);
    }
}
